package com.jumi.microservice.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jumi.microservice.common.constant.ResultEnum;
import com.jumi.microservice.common.context.SpringApplicationContext;
import com.jumi.microservice.common.exception.BaseException;
import com.jumi.microservice.constant.*;
import com.jumi.microservice.domain.*;
import com.jumi.microservice.domain.dto.PriorityDTO;
import com.jumi.microservice.domain.temp.PriorityTemp;
import com.jumi.microservice.domain.vo.*;
import com.jumi.microservice.mapper.*;
import com.jumi.microservice.service.PriorityService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限表 服务实现类
 * </p>
 *
 * @author liuz
 * @since 2020-07-18
 */
@Service
@Transactional
public class PriorityServiceImpl extends ServiceImpl<PriorityMapper, Priority> implements PriorityService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private RolePriorityRelationshipMapper rolePriorityRelationshipMapper;

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private DepartmentMapper departmentMapper;

    /**
     * spring容器组件
     */
    @Autowired
    private SpringApplicationContext context;

    /**
     * 新增菜单
     * @param dto 菜单信息
     */
    @Override
    public void insert(PriorityDTO dto) {
        Priority p = dto2Po(dto);
        ExceptionEnum.FAIL_NULL.doThrowIf(p==null);
        //判断权限标识唯一  未删除的 权限标识唯一
        int count = baseMapper.selectCount(
                Wrappers.<Priority>lambdaQuery()
                        .eq(Priority::getPriorityCode,p.getPriorityCode())
                        .eq(Priority::getIsDel,StatusEnum.STATUS_NO.getCode()));
        ExceptionEnum.FAIL_MENU_EXIST.doThrowIf(count> NumberConstant.NUMBER_ZERO);
        LocalDateTime now = LocalDateTime.now();
        p.setCreateTime(now);
        p.setUpdateTime(now);
        baseMapper.insert(p);
    }

    /**
     * 编辑菜单
     * @param dto 菜单信息
     */
    @Override
    public void update(PriorityDTO dto) {
        Priority p = dto2Po(dto);
        ExceptionEnum.FAIL_NULL.doThrowIf(p==null);
        //判断权限标识唯一  未删除的 权限标识唯一
        int count = baseMapper.selectCount(
                Wrappers.<Priority>lambdaQuery()
                        .eq(Priority::getPriorityCode,p.getPriorityCode())
                        .ne(Priority::getId,p.getId())
                        .eq(Priority::getIsDel,StatusEnum.STATUS_NO.getCode())
        );
        Priority po = baseMapper.selectById(p.getId());
        ExceptionEnum.FAIL_NULL.doThrowIf(po==null);
        //如果状态改变了才去进行校验
        if(!po.getStatus().equals(p.getStatus())) {
            if (1 == po.getStatus()) {
                List<PriorityCheckPo> list = baseMapper.selectChildList(po.getId());
                if(list.size()>0){
                    StringBuilder sb = new StringBuilder();
                    list.stream().forEach(ch -> {
                        sb.append(ch.getMenu_name()).append("|");
                    });
                    //子菜单未启用状态
                    throw new BaseException(new IResponseRxceptionCode(ResultEnum.FAIL.getCode(), StrUtil.format(ExceptionEnum.FAIL_PRI_STATUS_YES.getMessage(),sb.toString())));
                }
            } else {
                List<PriorityCheckPo> list = baseMapper.selectParentList(po.getId());
                if(list.size()>0){
                    //如果有父级菜单未启用 改为启用
                    list.stream().forEach(ch -> {
                        Priority poo = new Priority();
                        poo.setStatus(StatusEnum.STATUS_YES.getCode());
                        baseMapper.update(poo,
                                Wrappers.<Priority>lambdaUpdate()
                                        .eq(Priority::getId,ch.getMenu_id()));
                    });
                }
            }
        }
        ExceptionEnum.FAIL_MENU_EXIST.doThrowIf(count> NumberConstant.NUMBER_ZERO);
        p.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(p);
    }

    /**
     * 删除菜单
     * @param id 主键id
     * @param username 用户名
     */
    @Override
    public void delete(Long id, String username) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id==null);
        //校验
        Priority p = baseMapper.selectById(id);
        //是否启用状态
        ExceptionEnum.FAIL_STATUS.doThrowIf(p.getStatus()== StatusEnum.STATUS_YES.getCode());
        //是否存在未删除子菜单
        List<PriorityTemp> temps = baseMapper.selectChildren(id);
        ExceptionEnum.FAIL_HAS_CHILD.doThrowIf(temps.size()> NumberConstant.NUMBER_ZERO);
        //判断是否已绑定角色
        int count = roleMapper.selectCount(
                Wrappers.<Role>lambdaQuery()
                        .eq(Role::getIsDel, StatusEnum.STATUS_NO.getCode())
                        .apply("id in (select role_id from auth_role_priority_relationship where priority_id = "+id+" )"));
        ExceptionEnum.FAIL_HAS_ROLE.doThrowIf(count> NumberConstant.NUMBER_ZERO);
        p.setIsDel(StatusEnum.STATUS_YES.getCode());
        p.setUpdateTime(LocalDateTime.now());
        p.setModifier(username);
        baseMapper.updateById(p);
    }

    /**
     * 菜单详情
     * @param id 主键id
     * @return
     */
    @Override
    public PriorityDTO selectById(Long id) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id==null);
        Priority p = baseMapper.selectById(id);
        return po2Dto(p);
    }

    /**
     * 菜单启用/停用
     * @param id 主键id
     * @param status 状态
     */
    @Override
    public void enabledStatus(Long id, Integer status) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id==null);
        Priority p = baseMapper.selectById(id);
        ExceptionEnum.FAIL_NULL.doThrowIf(p==null);
        p.setStatus(status);
        p.setUpdateTime(LocalDateTime.now());
        //暂时写死
        p.setModifier("admin");
        baseMapper.updateById(p);
    }

    /**
     * 根据角色id获取权限
     * @param roleId 角色id
     * @return
     */
    @Override
    public JSONObject selectPriorsByRoleId(Long roleId) {
        JSONObject o = new JSONObject();
        Long st = System.currentTimeMillis();
        o.putOnce("msg",ResultEnum.SUCCESS.getMessage());
        o.putOnce("code",ResultEnum.SUCCESS.getCode());
        //先获取根目录
        List<Priority> list = baseMapper.selectList(
                Wrappers.<Priority>lambdaQuery()
                        .eq(Priority::getIsDel, StatusEnum.STATUS_NO.getCode())
                        .eq(Priority::getStatus,StatusEnum.STATUS_YES.getCode())
                        .eq(Priority::getPriorityType, PriorTypeEnum.MODULES.getCode()));
        //为筛选角色绑定的菜单 只返回最子级id
        List<Priority> roleCheck = new ArrayList<>();
        roleCheck.addAll(list);
        //获取子菜单
        List<RolePrioriVo> vos = list.stream().map(po -> {
            List<Priority> rolep = baseMapper.selectChild4Role(po.getId());
            roleCheck.addAll(rolep);
            RolePrioriVo vo = new RolePrioriVo();
            vo.setId(po.getId());
            vo.setLabel(po.getPriorityName());
            if(CollectionUtil.isNotEmpty(rolep)) {
                getChildren(vo, po, rolep);
            }
            return vo;
        }).collect(Collectors.toList());
        o.putOnce("menus",vos);
        //获取已绑定菜单id 如果roleid为null即为新增 还未绑定权限
        if(roleId!=null) {
            List<RolePriorityRelationship> rolePriorityPos = rolePriorityRelationshipMapper.selectList(
                    Wrappers.<RolePriorityRelationship>lambdaQuery()
                            .eq(RolePriorityRelationship::getRoleId, roleId));
            //获取角色下所有的权限id
            if (CollectionUtil.isNotEmpty(rolePriorityPos)) {
                List<Integer> prors = rolePriorityPos.stream().map(r -> {
                    Integer id = r.getPriorityId();
                    return id;
                }).collect(Collectors.toList());
               o.putOnce("checkedKeys", packPriorsIdByNoParent(prors, roleCheck));
            }
        }
        System.out.println((System.currentTimeMillis())-st);
        return o;
    }

    /**
     * 根据登录用户获取菜单
     * @param accountId 用户id
     * @return
     */
    @Override
    public List<PriorityRVO> authorizeList(Long accountId) {
        List<Priority> priorities = null;
        try {
            //根据用户角色权限绑定关系获取权限id
            List<Integer> priorids = baseMapper.selectAllPriByAccountId(accountId);
            priorities = baseMapper.authorizeList(accountId, null);
            //递归方式来获取菜单列表
            //20200822 按前端说法修改 系统管理属于模块 子级类型直接为菜单 不需要再添加目录级别
            getChildrenPO(priorities,accountId,priorids);
        }catch (Exception e){
            e.printStackTrace();
        }
        return pos2Rvos(priorities);
    }

    /**
     * 查询权限列表
     * @param vo 条件查询
     * @return
     */
    @Override
    public List<Priority> getRootList(PriorityVO vo) {
        long time = System.currentTimeMillis();
        //获取根目录
        List<Priority> pos = baseMapper.selectList(
                Wrappers.<Priority>lambdaQuery()
                        .like(StringUtils.isNotEmpty(vo.getPriorityName()),Priority::getPriorityName,vo.getPriorityName())
                        .eq(vo.getStatus()!=null, Priority::getStatus,vo.getStatus())
                        .ge(StringUtils.isNotEmpty(vo.getStartTimeAdd()), Priority::getCreateTime,vo.getStartTimeAdd())
                        .le(StringUtils.isNotEmpty(vo.getEndTimeAdd()), Priority::getCreateTime,vo.getEndTimeAdd())
                        .ge(StringUtils.isNotEmpty(vo.getStartTimeUp()), Priority::getUpdateTime,vo.getStartTimeUp())
                        .le(StringUtils.isNotEmpty(vo.getEndTimeUp()), Priority::getUpdateTime,vo.getEndTimeUp())
                        .eq(Priority::getIsDel, StatusEnum.STATUS_NO.getCode())
                        .eq(vo.getStatus()!=null,Priority::getStatus, vo.getStatus())
                        .orderByDesc(Priority::getOrderNum,Priority::getUpdateTime));
        ExceptionEnum.FAIL_PRIOR_NULL.doThrowIf(pos==null||pos.size()==0);
        //获取所有的id的parent菜单
        if(StringUtils.isNotEmpty(vo.getPriorityName())) {
            List<Priority> newpos = new ArrayList<>();
            for (Priority p: pos) {
                newpos.add(p);
                getParent(p,newpos);
            }
            List<Priority> newposs =
                    newpos.stream()
                            .distinct()
                            .sorted(Comparator.comparing(Priority::getOrderNum)
                                              .thenComparing(Priority::getUpdateTime).reversed())
                            .collect(Collectors.toList());
            System.out.println("执行时间: =============================="+(System.currentTimeMillis()-time));
            return newposs;
        }
        return pos;
    }

    @Override
    public JSONObject getInfo(Long accountId) {
        JSONObject o = new JSONObject();
        o.putOnce("code", ResultEnum.SUCCESS.getCode());
        o.putOnce("msg",ResultEnum.SUCCESS.getMessage());
        //获取登录用户信息
        Account account = accountMapper.selectOne(
                Wrappers.<Account>lambdaQuery()
                        .eq(Account::getUid,accountId));
        UserAccountEnum.USER_NOT_EXISTED.doThrowIf(account==null);
        //获取用户部门信息
        Department department = departmentMapper.selectById(account.getDepartmentId());
        //获取绑定角色信息
        List<Role> list = roleMapper.selectList(
                Wrappers.<Role>lambdaQuery()
                        .apply("id in (select role_id from auth_account_role_relationship where account_id = "+accountId+")")
                        .eq(Role::getStatus,StatusEnum.STATUS_YES.getCode())
                        .eq(Role::getIsDel,StatusEnum.STATUS_NO.getCode()));
        UserVO user = new UserVO();
        user.setAccount(account);
        user.setDepartment(department);
        user.setRoles(list);
        o.putOnce("user",user);
        //获取绑定的权限信息
        List<String> ps = baseMapper.selectHasP(accountId);
        o.putOnce("permissions",ps);
        return o;
    }

    /**
     * 对象转换 dto->do
     * @param dto
     * @return
     */
    private Priority dto2Po(PriorityDTO dto){
        Priority r = null;
        try {
            r = dto.clone(Priority.class);
        }catch (Exception e){
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return r;
    }

    /**
     * 对象转换 po->dto
     * @param po
     * @return
     */
    private PriorityDTO po2Dto(Priority po){
        PriorityDTO r = null;
        try {
            r = po.clone(PriorityDTO.class);
        }catch (Exception e){
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return r;
    }

    /**
     * 根据父菜单获取子菜单
     * @param vo
     */
    private void getChildren(RolePrioriVo vo, Priority po, List<Priority> priors){
        //获取当前的子菜单
//       List<Priority> list = baseMapper.selectList(
//               Wrappers.<Priority>lambdaQuery()
//                       .eq(Priority::getParentId,vo.getId())
//                       .eq(Priority::getStatus, StatusEnum.STATUS_YES.getCode()));
//       List<RolePrioriVo> vos = list.stream().map(p->{
//           RolePrioriVo vop = new RolePrioriVo();
//           vop.setId(p.getId());
//           vop.setLabel(p.getPriorityName());
//           getChildren(vop);
//           return vop;
//       }).collect(Collectors.toList());
//       if(vos.size()>0) {
//           vo.setChildren(vos);
//       }
        List<Priority> prioritys = priors.stream().filter(p->p.getParentId()==po.getId().intValue()).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(prioritys)){
            List<RolePrioriVo> list = prioritys.stream().map(p->{
                RolePrioriVo rolePrioriVo = new RolePrioriVo();
                rolePrioriVo.setId(p.getId());
                rolePrioriVo.setLabel(p.getPriorityName());
                getChildren(rolePrioriVo, p, priors);
                return rolePrioriVo;
            }).collect(Collectors.toList());
            vo.setChildren(list);
        }
    }

    /**
     * 根据父菜单获取子菜单
     * @param priorities 父级菜单列表
     * @param accountId 用户id
     * @param priorids 用户绑定的菜单id
     */
    private void getChildrenPO( List<Priority> priorities, Long accountId, List<Integer> priorids){
        //获取当前的子菜单 除去按钮
        priorities.stream().forEach(p->{
            List<Priority> pr = baseMapper.selectList(
                    Wrappers.<Priority>lambdaQuery()
                            .eq(Priority::getParentId,p.getId())
                            .eq(Priority::getStatus,StatusEnum.STATUS_YES.getCode())
                            .eq(Priority::getIsDel,StatusEnum.STATUS_NO.getCode())
                            .ne(Priority::getPriorityType, PriorTypeEnum.BUTTON.getCode())
                            .orderByDesc(Priority::getOrderNum,Priority::getUpdateTime));
            //过滤未绑定的菜单
            List<Priority> newpr = pr.stream().filter(pps->priorids.contains(pps.getId())).collect(Collectors.toList());
            getChildrenPO(newpr, accountId, priorids);
            p.setChildren(newpr);
        });
    }

    /**
     * po->vo
     * @param p
     * @return
     */
    private PriorityVO po2Vo(Priority p){
        PriorityVO vo = null;{
            try {
                vo = p.clone(PriorityVO.class);
            }catch (Exception e){
                ExceptionEnum.FAIL_CHANGE.newException();
            }
        }
        return vo;
    }

    /**
     * 获取父级菜单
     * @param po
     * @param pos
     * @return
     */
    private  List<Priority> getParent(Priority po,List<Priority> pos){
        Priority pop = baseMapper.selectOne(
                Wrappers.<Priority>lambdaQuery()
                        .eq(Priority::getId,po.getParentId())
                        .eq(Priority::getIsDel, StatusEnum.STATUS_NO.getCode())
                        .orderByDesc(Priority::getOrderNum,Priority::getUpdateTime));
        if(pop!=null){
            pos.add(pop);
            getParent(pop,pos);
        }
        return pos;
    }

    /**
     * vo->po
     * @param vos
     * @return
     */
    private List<Priority> vos2Pos(List<PriorityVO> vos){
        List<Priority> pos = vos.stream().map(v->{
            Priority po = null;{
                try {
                    po = v.clone(Priority.class);
                }catch (Exception e){
                    ExceptionEnum.FAIL_CHANGE.newException();
                }
            }
            return po;
        }).collect(Collectors.toList());
        return pos;
    }

    /**
     * po转前端需要格式
     * @param pos
     * @return
     */
    private List<PriorityRVO> pos2Rvos(List<Priority> pos){
        return pos.stream().map(p->{
            PriorityRVO rvo = new PriorityRVO();
            MetaVo metaVo = new MetaVo();
            metaVo.setTitle(p.getPriorityName());
            metaVo.setIcon(p.getIcon());
            rvo.setMeta(metaVo);
            rvo.setPath(p.getPath());
            rvo.setChildren(pos2Rvos(p.getChildren()));
            rvo.setHidden(p.getHidden()==StatusEnum.STATUS_YES.getCode()?true:false);
            rvo.setPriorityCode(p.getPriorityCode());
            //目录模块不需要返回路径
            if((PriorTypeEnum.DIRECTORY.getCode().equals(p.getPriorityType()))||(PriorTypeEnum.MODULES.getCode().equals(p.getPriorityType()))){
                rvo.setAlwaysShow(true);
                rvo.setComponent(RedirectType.LAY_OUT);
                rvo.setRedirect(RedirectType.NO_REDIRECT);
                //name取/后首单词
                if (p.getPath().startsWith("/")) {
                    rvo.setName(upperCase(p.getPath().substring(p.getPath().indexOf("/") + 1)));
                } else {
                    rvo.setName(upperCase(p.getPath()));
                }
            }else {
                rvo.setName(upperCase(p.getPath().substring(p.getPath().lastIndexOf("/") + 1)));
                rvo.setRedirect(null);
            }
            //单独处理组件路径
            if((PriorTypeEnum.DIRECTORY.getCode().equals(p.getPriorityType()))||(PriorTypeEnum.MENU.getCode().equals(p.getPriorityType()))){
                rvo.setComponent(p.getComponent());
            }
            if(p.getChildren()==null||p.getChildren().size()==0){
                rvo.setAlwaysShow(false);
            }
            return rvo;
        }).collect(Collectors.toList());
    }

    /**
     * 首字母大写处理
     * @param str
     * @return
     */
    public String upperCase(String str) {
        if(StringUtils.isEmpty(str)){
            return null;
        }
        char[] ch = str.toCharArray();
        if (ch[0] >= 'a' && ch[0] <= 'z') {
            ch[0] = (char) (ch[0] - 32);
        }
        return new String(ch);
    }

    /**
     * 封装角色绑定权限 最终子级
     * @param prors 角色绑定的权限id
     * @param roleCheck 菜单信息
     * @return
     */
    private List<Integer> packPriorsIdByNoParent(List<Integer> prors, List<Priority> roleCheck){
        List<Integer> ids = new ArrayList<>();
        prors.stream().forEach(p->{
            if(!roleCheck.stream().filter(ro->ro.getParentId().intValue()==p).findAny().isPresent()){
                ids.add(p);
            }
        });
        return ids;
    }
}
